﻿using AiMoRhino.ScriptInstance.CustomGetter;
using Rhino;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Input.Custom;
using System.Collections.Generic;
using System.Linq;

namespace AiMoCore
{
    partial class CSharpScriptInstance
    {
        void ClearSelect()
        {
            RhinoDoc.ActiveDoc.Objects.UnselectAll();
        }
        public bool Select(out RhinoObject[] rhinoObjects) => Select(out rhinoObjects, ObjectType.AnyObject, "");
        public bool Select(out RhinoObject[] rhinoObjects, ObjectType objectType) => Select(out rhinoObjects, objectType, "");
        /// <summary>
        /// 选取多个Rhino物体，可以指定选择的ObjectType。
        /// 成功返回True。
        /// </summary>
        public bool Select(out RhinoObject[] rhinoObjects, ObjectType objectType, string prompts)
        {
            GetObject get = new GetObject();
            if (string.IsNullOrEmpty(prompts)) prompts = $"请选择多个物体：{objectType}";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.GeometryFilter = objectType;
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
                rhinoObjects = get.Objects().Select(x => x.Object()).ToArray();
            else
                rhinoObjects = null;
            ClearSelect();
            return re;
        }
        public bool Select(out RhinoObject rhinoObject) => Select(out rhinoObject, ObjectType.AnyObject, "");
        public bool Select(out RhinoObject rhinoObject, ObjectType objectType) => Select(out rhinoObject, objectType, "");
        /// <summary>
        /// 选取一个Rhino物体，可以指定选择的ObjectType。
        /// 成功返回True。
        /// </summary>
        public bool Select(out RhinoObject rhinoObject, ObjectType objectType, string prompts)
        {
            GetObject get = new GetObject();
            if (string.IsNullOrEmpty(prompts)) prompts = $"请选择一个物体：{objectType}";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.GeometryFilter = objectType;
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
                rhinoObject = get.Object(0).Object();
            else
                rhinoObject = null;
            ClearSelect();
            return re;
        }
        public bool Select(out Polyline polyline) => Select(out polyline, "");
        /// <summary>
        /// 选取一个多段线，如果成功返回True
        /// </summary>
        public bool Select(out Polyline polyline, string prompts)
        {
            GetPolylineObject get = new GetPolylineObject();
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择一个多段线";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;

            if (re)
            {
                Curve curve = get.Object(0).Object().Geometry as Curve;
                if (curve.TryGetPolyline(out polyline)) return true;
            }
            polyline = null;
            ClearSelect();
            return false;
        }
        public bool Select(out Polyline[] polylines) => Select(out polylines, "");
        /// <summary>
        /// 选取多个多段线，如果成功返回True
        /// </summary>
        public bool Select(out Polyline[] polylines, string prompts)
        {
            GetPolylineObject get = new GetPolylineObject();
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择多个多段线";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            List<Polyline> list = new List<Polyline>();
            if (re)
            {
                foreach (var obj in get.Objects())
                {
                    if (obj.Object().Geometry is Curve crv && crv.TryGetPolyline(out Polyline pl))
                    {
                        list.Add(pl);
                    }
                }
            }
            polylines = list.ToArray();
            ClearSelect();
            return list.Count > 0;
        }

        public bool Select(out Circle[] circles) => Select(out circles, "");
        public bool Select(out Circle[] circles, string prompts)
        {
            GetCircleObject get = new GetCircleObject();
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择多个圆";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            List<Circle> list = new List<Circle>();
            if (re)
            {
                foreach (var obj in get.Objects())
                {
                    if (obj.Object().Geometry is Curve crv && crv.TryGetCircle(out Circle cir))
                    {
                        list.Add(cir);
                    }
                }
            }
            circles = list.ToArray();
            ClearSelect();
            return list.Count > 0;
        }
        public bool Select(out Circle circle) => Select(out circle, "");
        public bool Select(out Circle circle, string prompts)
        {
            GetCircleObject get = new GetCircleObject();
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择一个圆";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
            {
                Curve curve = get.Object(0).Object().Geometry as Curve;
                if (curve.TryGetCircle(out circle)) return true;
            }
            circle = Circle.Unset;
            ClearSelect();
            return false;
        }
        public bool Select(out Line[] lines) => Select(out lines, "");
        public bool Select(out Line[] lines, string prompts)
        {
            GetLineObject get = new GetLineObject();
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择多个线段";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            List<Line> list = new List<Line>();
            if (re)
            {
                foreach (var obj in get.Objects())
                {
                    if (obj.Object().Geometry is Curve crv)
                    {
                        list.Add(new Line(crv.PointAtStart, crv.PointAtEnd));
                    }
                }
            }
            lines = list.ToArray();
            ClearSelect();
            return list.Count > 0;
        }
        public bool Select(out Line line) => Select(out line, "");
        public bool Select(out Line line, string prompts)
        {
            GetLineObject get = new GetLineObject();
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择一个线段";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
            {
                Curve crv = get.Object(0).Object().Geometry as Curve;
                line = new Line(crv.PointAtStart, crv.PointAtEnd);

            }
            else line = Line.Unset;
            ClearSelect();
            return re;
        }
        public bool Select(out Curve[] curves) => Select(out curves, "");
        /// <summary>
        /// 选取多个曲线，如果成功返回True
        /// </summary>
        public bool Select(out Curve[] curve, string prompts)
        {
            curve = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Curve, prompts);
            if (re)
            {
                curve = objs.Select(x => x.Geometry as Curve).ToArray();
            }
            return re;
        }
        public bool Select(out Curve curve) => Select(out curve, "");
        /// <summary>
        /// 选取一个曲线，如果成功返回True
        /// </summary>
        public bool Select(out Curve curve, string prompts)
        {
            curve = null;
            bool re = Select(out RhinoObject obj, ObjectType.Curve, prompts);
            if (re)
            {
                curve = obj.Geometry as Curve;
            }
            return re;
        }
        public bool Select(out Mesh[] meshes) => Select(out meshes, "");
        /// <summary>
        /// 选取多个网格，如果成功返回True
        /// </summary>
        public bool Select(out Mesh[] meshes, string prompts)
        {
            meshes = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Mesh, prompts);
            if (re)
            {
                meshes = objs.Select(x => x.Geometry as Mesh).ToArray();
            }
            return re;
        }
        public bool Select(out Mesh mesh) => Select(out mesh, "");
        /// <summary>
        /// 选取一个网格，如果成功返回True
        /// </summary>
        public bool Select(out Mesh mesh, string prompts)
        {
            mesh = null;
            bool re = Select(out RhinoObject obj, ObjectType.Mesh, prompts);
            if (re)
            {
                mesh = obj.Geometry as Mesh;
            }
            return re;
        }
        public bool Select(out Brep[] breps) => Select(out breps, "");
        /// <summary>
        /// 选取多个多重曲面，如果成功返回True
        /// </summary>
        public bool Select(out Brep[] breps, string prompts)
        {
            breps = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Brep, prompts);
            if (re)
            {
                breps = objs.Select(x => ToBrep(x.Geometry)).ToArray();
            }
            return re && breps.All(x => x is Brep);
        }
        public bool Select(out Brep brep) => Select(out brep, "");
        /// <summary>
        /// 选取一个多重曲面，如果成功返回True
        /// </summary>
        public bool Select(out Brep brep, string prompts)
        {
            brep = null;
            bool re = Select(out RhinoObject obj, ObjectType.Brep, prompts);
            if (re)
            {
                brep = ToBrep(obj.Geometry);
            }
            return re && brep != null;
        }
        Brep ToBrep(GeometryBase geo)
        {
            Brep bp = geo as Brep;
            if (bp == null)
            {
                if (geo is Extrusion extrusion)
                {
                    bp = extrusion.ToBrep();
                }
            }
            return bp;
        }
        public bool Select(out Extrusion[] extrusions) => Select(out extrusions, "");
        /// <summary>
        /// 选取多个挤出物件，如果成功返回True
        /// </summary>
        public bool Select(out Extrusion[] extrusions, string prompts)
        {
            extrusions = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Extrusion, prompts);
            if (re)
            {
                extrusions = objs.Select(x => x.Geometry as Extrusion).ToArray();
            }
            return re;
        }
        public bool Select(out Extrusion extrusion) => Select(out extrusion, "");
        /// <summary>
        /// 选取一个挤出物件，如果成功返回True
        /// </summary>
        public bool Select(out Extrusion extrusion, string prompts)
        {
            extrusion = null;
            bool re = Select(out RhinoObject obj, ObjectType.Extrusion, prompts);
            if (re)
            {
                extrusion = obj.Geometry as Extrusion;
            }
            return re;
        }
        public bool Select(out Surface[] surfaces) => Select(out surfaces, "");
        /// <summary>
        /// 选取多个曲面，如果成功返回True
        /// </summary>
        public bool Select(out Surface[] surfaces, string prompts)
        {
            surfaces = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.Surface, prompts);
            if (re)
            {
                surfaces = objs.Select(x => x.Geometry as Surface).ToArray();
            }
            return re;
        }
        public bool Select(out Surface surface) => Select(out surface, "");
        /// <summary>
        /// 选取一个曲面，如果成功返回True
        /// </summary>
        public bool Select(out Surface surface, string prompts)
        {
            surface = null;
            bool re = Select(out RhinoObject obj, ObjectType.Surface, prompts);
            if (re)
            {
                surface = obj.Geometry as Surface;
            }
            return re;
        }
        public bool Select(out InstanceObject[] instanceObjects) => Select(out instanceObjects, "");
        /// <summary>
        /// 选取多个图块物体，如果成功返回True
        /// </summary>
        public bool Select(out InstanceObject[] instanceObjects, string prompts)
        {
            instanceObjects = null;
            bool re = Select(out RhinoObject[] objs, ObjectType.InstanceReference, prompts);
            if (re)
            {
                instanceObjects = objs.Cast<InstanceObject>().ToArray();
            }
            return re;
        }
        public bool Select(out InstanceObject instanceObject) => Select(out instanceObject, "");
        /// <summary>
        /// 选取一个图块物体，如果成功返回True
        /// </summary>
        public bool Select(out InstanceObject instanceObject, string prompts)
        {
            instanceObject = null;
            bool re = Select(out RhinoObject obj, ObjectType.InstanceReference, prompts);
            if (re)
            {
                instanceObject = obj as InstanceObject;
            }
            return re;
        }
        public bool Select(out TextEntity text) => Select(out text, "");
        public bool Select(out TextEntity text, string prompts)
        {
            GetTextEntityObject get = new GetTextEntityObject();
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择一个文字";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.Get() == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            if (re)
            {
                text = get.Object(0).Object().Geometry as TextEntity;
            }
            else text = null;
            ClearSelect();
            return re;
        }
        public bool Select(out TextEntity[] texts) => Select(out texts, "");
        public bool Select(out TextEntity[] texts, string prompts)
        {
            GetTextEntityObject get = new GetTextEntityObject();
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择多个文字";
            get.SetCommandPrompt(prompts);
            get.EnablePreSelect(true, true);
            get.SubObjectSelect = false;
            bool re = get.GetMultiple(1, 0) == Rhino.Input.GetResult.Object && get.ObjectCount > 0;
            List<TextEntity> list = new List<TextEntity>();
            if (re)
            {
                foreach (var obj in get.Objects())
                {
                    if (obj.Object().Geometry is TextEntity text)
                    {
                        list.Add(text);
                    }
                }
            }
            texts = list.ToArray();
            ClearSelect();
            return list.Count > 0;
        }
        public bool Select(out Point3d pt) => Select(out pt, "");
        public bool Select(out Point3d pt, string prompts)
        {
            pt = Point3d.Unset;
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择点";
            bool re = Select(out RhinoObject obj, ObjectType.Point, prompts);
            if (re)
            {
                Point ptGeo = obj.Geometry as Point;
                if (ptGeo != null)
                    pt = ptGeo.Location;
            }
            return pt.IsValid;
        }
        public bool Select(out Point3d[] pts) => Select(out pts, "");
        public bool Select(out Point3d[] pts, string prompts)
        {
            pts = null;
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择多个点";
            bool re = Select(out RhinoObject[] objs, ObjectType.Point, prompts);
            if (re)
            {
                pts = objs.Select(x => x.Geometry).Cast<Point>().Select(x => x.Location).ToArray();
            }
            return re;
        }

        public bool Select(out GeometryBase geo) => Select(out geo, "");
        public bool Select(out GeometryBase geo, string prompts)
        {
            geo = null;
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择GeometryBase";
            bool re = Select(out RhinoObject rhinoObject, ObjectType.AnyObject, prompts);
            if (re)
            {
                geo = rhinoObject.Geometry;
            }
            return geo != null;
        }

        public bool Select(out GeometryBase[] geos) => Select(out geos, "");
        public bool Select(out GeometryBase[] geos, string prompts)
        {
            geos = null;
            if (string.IsNullOrEmpty(prompts)) prompts = "请选择多个GeometryBase";
            bool re = Select(out RhinoObject[] rhinoObjects, ObjectType.AnyObject, prompts);
            if (re)
            {
                geos = rhinoObjects.Select(x => x.Geometry).ToArray();
            }
            return re;
        }
    }
}
